(function (fruit, util) {
    var rpatt = /(?=[{])\{([^{}]+?)\}(?![}])/g;
    var rwrap = /([{}]){2}/g;

    function formatData(formatter, inData, callback) {
        var array = formatter._array.slice(0);
        var i, key, keys = formatter.keys(), length;
        if (keys) {
            length = keys.length;
            for (i = 0; i < length; i++) {
                key = keys[i];
                array[key.index] = callback.call(this, i, key, inData);
            }
        }
        return array.join("");
    }

    /**
     * @class fruit.Formatter
     */

    fruit.define("fruit.Formatter", {
        statics:{
            create:function (inText, inData) {
                var formatter = new fruit.Formatter(inText, inData);
                if (formatter.keys) {
                    return formatter;
                }
                return null;
            }
        },
        properties:{
            keys:{
                readonly:true
            },
            onlyKey:{
                value:false,
                readonly:true
            }
        },
        methods:{
            init:function (inText) {
                var ret, retItem, retIndex, itemLen, keys, array;
                var keyIndex = 0;
                var arrIndex = 0;
                if (inText) {
                    this.keys([]);
                    keys = this.keys();
                    array = this._array = [];
                    while ((ret = rpatt.exec(inText)) !== null) {
                        retItem = ret[1];
                        retIndex = ret.index;
                        itemLen = retIndex + retItem.length + 2;
                        if (retIndex) {
                            arrIndex = array.push(this.filterDoubleDelimit(inText, keyIndex, retIndex), retItem);
                        } else {
                            arrIndex = array.push(retItem);
                        }
                        keyIndex = itemLen;
                        keys.push({
                            index:arrIndex - 1,
                            path:retItem
                        });
                    }
                    array.push(this.filterDoubleDelimit(inText, keyIndex));
                    this._initOnlyKey();
                }
            },
            _initOnlyKey:function () {
                if (this.keys().length === 1 && this._array[1] === "") {
                    this.onlyKey(true);
                }
            },
            filterDoubleDelimit:function (inText, start, end) {
                if (inText === "{}") {
                    return "";
                }
                return inText.substring(start, end).replace(rwrap, "$1");
            },
            /**
             * get argument's format data
             * @returns {*}
             */
            format:function () {
                var args = arguments;
                return formatData(this, null, function (index) {
                    return args[index];
                });
            },
            /**
             * get argument's data
             * @param inData
             * @returns {*}
             */
            formatObj:function (inData) {
                return formatData(this, inData, function (index, key, inData) {
                    return util.getByPath(key.path, inData || {});
                });
            }
        }
    });
})(fruit, fruit.util);